// exception.cc 
//	Entry point into the Nachos kernel from user programs.
//	There are two kinds of things that can cause control to
//	transfer back to here from user code:
//
//	syscall -- The user code explicitly requests to call a procedure
//	in the Nachos kernel.  Right now, the only function we support is
//	"Halt".
//
//	exceptions -- The user code does something that the CPU can't handle.
//	For instance, accessing memory that doesn't exist, arithmetic errors,
//	etc.  
//
//	Interrupts (which can also cause control to transfer from user
//	code into the Nachos kernel) are handled elsewhere.
//
// For now, this only handles the Halt() system call.
// Everything else core dumps.
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "system.h"
#include "syscall.h"
#include "synch.h"
#include "../network/client.h"
#include <stdio.h>
#include <iostream>
void kernel_thread(int);
int handleIPTMiss(int);

using namespace std;

int copyin(unsigned int vaddr, int len, char *buf) {
    // Copy len bytes from the current thread's virtual address vaddr.
    // Return the number of bytes so read, or -1 if an error occors.
    // Errors can generally mean a bad virtual address was passed in.
    bool result;
    int n=0;			// The number of bytes copied in
    int *paddr = new int;

    while ( n >= 0 && n < len) {
      result = machine->ReadMem( vaddr, 1, paddr );
      while(!result) // FALL 09 CHANGES
	  {
   			result = machine->ReadMem( vaddr, 1, paddr ); // FALL 09 CHANGES: TO HANDLE PAGE FAULT IN THE ReadMem SYS CALL
	  }	
      
      buf[n++] = *paddr;
     
      if ( !result ) {
	//translation failed
	return -1;
      }

      vaddr++;
    }

    delete paddr;
    return len;
}

int copyout(unsigned int vaddr, int len, char *buf) {
    // Copy len bytes to the current thread's virtual address vaddr.
    // Return the number of bytes so written, or -1 if an error
    // occors.  Errors can generally mean a bad virtual address was
    // passed in.
    bool result;
    int n=0;			// The number of bytes copied in

    while ( n >= 0 && n < len) {
      // Note that we check every byte's address
      result = machine->WriteMem( vaddr, 1, (int)(buf[n++]) );

      if ( !result ) {
	//translation failed
	return -1;
      }

      vaddr++;
    }

    return n;
}

void Create_Syscall(unsigned int vaddr, int len) {
    // Create the file with the name in the user buffer pointed to by
    // vaddr.  The file name is at most MAXFILENAME chars long.  No
    // way to return errors, though...
    char *buf = new char[len+1];	// Kernel buffer to put the name in

    if (!buf) return;

    if( copyin(vaddr,len,buf) == -1 ) {
	printf("%s","Bad pointer passed to Create\n");
	delete buf;
	return;
    }

    buf[len]='\0';

    fileSystem->Create(buf,0);
    delete[] buf;
    return;
}

int Open_Syscall(unsigned int vaddr, int len) {
    // Open the file with the name in the user buffer pointed to by
    // vaddr.  The file name is at most MAXFILENAME chars long.  If
    // the file is opened successfully, it is put in the address
    // space's file table and an id returned that can find the file
    // later.  If there are any errors, -1 is returned.
    char *buf = new char[len+1];	// Kernel buffer to put the name in
    OpenFile *f;			// The new open file
    int id;				// The openfile id

    if (!buf) {
	printf("%s","Can't allocate kernel buffer in Open\n");
	return -1;
    }

    if( copyin(vaddr,len,buf) == -1 ) {
	printf("%s","Bad pointer passed to Open\n");
	delete[] buf;
	return -1;
    }

    buf[len]='\0';

    f = fileSystem->Open(buf);
    delete[] buf;

    if ( f ) {
	if ((id = currentThread->space->fileTable.Put(f)) == -1 )
	    delete f;
	return id;
    }
    else
	return -1;
}

void Write_Syscall(unsigned int vaddr, int len, int id) {
    // Write the buffer to the given disk file.  If ConsoleOutput is
    // the fileID, data goes to the synchronized console instead.  If
    // a Write arrives for the synchronized Console, and no such
    // console exists, create one. For disk files, the file is looked
    // up in the current address space's open file table and used as
    // the target of the write.
    
    char *buf;		// Kernel buffer for output
    OpenFile *f;	// Open file for output

    if ( id == ConsoleInput) return;
    
		if ( !(buf = new char[len]) ) {
			printf("%s","Error allocating kernel buffer for write!\n");
			return;
		} else {
			if ( copyin(vaddr,len,buf) == -1 ) {
			printf("%s","Bad pointer passed to to write: data not written\n");
			delete[] buf;
			return;
		}
    }
	printf("Process %i: ",*currentThread->processId);
    if ( id == ConsoleOutput) {
		for (int ii=0; ii<len; ii++) {
			printf("%c",buf[ii]);
		}

    } else {
		if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
			f->Write(buf, len);
		} else {
			printf("%s","Bad OpenFileId passed to Write\n");
			len = -1;
		}
    }

    delete[] buf;
}

void Write1_Syscall(unsigned int vaddr, int len, int id, int arg) {
    // Write the buffer to the given disk file.  If ConsoleOutput is
    // the fileID, data goes to the synchronized console instead.  If
    // a Write arrives for the synchronized Console, and no such
    // console exists, create one. For disk files, the file is looked
    // up in the current address space's open file table and used as
    // the target of the write.
    
    char *buf;		// Kernel buffer for output
    OpenFile *f;	// Open file for output

    if ( id == ConsoleInput) return;
    
		if ( !(buf = new char[len]) ) {
			printf("%s","Error allocating kernel buffer for write!\n");
			return;
		} else {
			if ( copyin(vaddr,len,buf) == -1 ) {
			printf("%s","Bad pointer passed to to write: data not written\n");
			delete[] buf;
			return;
		}
    }

	printf("Process %i: ",*currentThread->processId);
    try {
		printf(buf, arg);
    }
    catch(int e){
	printf("NONONO. You are using Write1 incorrectly. Stop that.\n");
    }

    delete[] buf;
}

int Read_Syscall(unsigned int vaddr, int len, int id) {
    // Write the buffer to the given disk file.  If ConsoleOutput is
    // the fileID, data goes to the synchronized console instead.  If
    // a Write arrives for the synchronized Console, and no such
    // console exists, create one.    We reuse len as the number of bytes
    // read, which is an unnessecary savings of space.
    char *buf;		// Kernel buffer for input
    OpenFile *f;	// Open file for output

    if ( id == ConsoleOutput) return -1;
    
    if ( !(buf = new char[len]) ) {
	printf("%s","Error allocating kernel buffer in Read\n");
	return -1;
    }

    if ( id == ConsoleInput) {
      //Reading from the keyboard
      scanf("%s", buf);

      if ( copyout(vaddr, len, buf) == -1 ) {
	printf("%s","Bad pointer passed to Read: data not copied\n");
      }
    } else {
	if ( (f = (OpenFile *) currentThread->space->fileTable.Get(id)) ) {
	    len = f->Read(buf, len);
	    if ( len > 0 ) {
	        //Read something from the file. Put into user's address space
  	        if ( copyout(vaddr, len, buf) == -1 ) {
		    printf("%s","Bad pointer passed to Read: data not copied\n");
		}
	    }
	} else {
	    printf("%s","Bad OpenFileId passed to Read\n");
	    len = -1;
	}
    }

    delete[] buf;
    return len;
}

void Close_Syscall(int fd) {
    // Close the file associated with id fd.  No error reporting.
    OpenFile *f = (OpenFile *) currentThread->space->fileTable.Remove(fd);

    if ( f ) {
      delete f;
    } else {
      printf("%s","Tried to close an unopen file\n");
    }
}

void Yield()
{
	currentThread->Yield();
}

//syscall #11
int LockCreate_Syscall(unsigned int vaddr, int len) {
	kernelLockTableLock->Acquire();
	char *buf;
	
	/*makes buf a character array of size len (so it can be used) or returns*/
	if ( !(buf = new char[len+1]) ) {
		printf("%s","Error allocating kernel buffer in Create Lock\n");
		kernelLockTableLock->Release();
		return(-1);
	}
	
	/*copies the data from the virtual address (hopefully the lock name) into buf*/
	if ( copyin(vaddr, len, buf) == -1 ) {
		printf("%s","Bad pointer passed to Create Lock: data not copied\n");
		delete[] buf;
		kernelLockTableLock->Release();
		return(-1);
	}
	
	#ifdef NETWORK
	    int rv = ClientCreateLock(buf);
		networkLocks[*currentThread->processId][rv] = buf;
		return rv;
	#endif
	
	/*find empty space in bitmap*/
	nextLockLocation = freeKernelLockBmp->Find();

	/*if no free space for locks, then let the user know*/
	if(nextLockLocation == -1) {
		printf("No more free spaces. You have reached the maximum number of locks! New locks cannot be made until other locks are deleted.\n");
		kernelLockTableLock->Release();
		return(-1);
	}
	
	/*if we found a free space, make a new lock*/
	
	buf[len] = '\0';
	printf("Making new lock named %s\nIt's position in the kernelLocks is %i\n", buf, nextLockLocation);
	/*no errors, so make the lock and add it to the global array of locks*/
	kernelLocks[*currentThread->processId][nextLockLocation] = new KernelLock();
	kernelLocks[*currentThread->processId][nextLockLocation]->lock = new Lock(buf);
	kernelLocks[*currentThread->processId][nextLockLocation]->addrSpace = currentThread->space;
	kernelLocks[*currentThread->processId][nextLockLocation]->isToBeDeleted = false;
	kernelLocks[*currentThread->processId][nextLockLocation]->isDeleted = false;

	kernelLockTableLock->Release();
	
	/*return the int so the process can use the lock*/
	return(nextLockLocation);
}

//syscall #12
void LockAcquire_Syscall(int lockNum) {
	kernelLockTableLock->Acquire();

	/*check if the lock has been initialized*/
	if(kernelLocks[*currentThread->processId][lockNum] == NULL) {
		printf("Lock %i has not been initialized.\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}
	
	/*check if this process can access this lock by checking the address space*/
	if(kernelLocks[*currentThread->processId][lockNum]->addrSpace != currentThread->space) {
		/*printf("You do not own that lock. Thread#: %i, Lock#: %i\n", kernelLocks[*currentThread->processId][lockNum]->addrSpace, currentThread->space);*/
		printf("You do not own that lock.\n");
		kernelLockTableLock->Release();
		return;
	}
	/*check if that lock has been deleted*/
	if(kernelLocks[*currentThread->processId][lockNum]->isDeleted == true || kernelLocks[*currentThread->processId][lockNum]->isToBeDeleted == true) {
		printf("That lock has been deleted. Zombification will not be tolerated.\n");
		kernelLockTableLock->Release();
		return;
	}

	if(lockNum < 0 || lockNum > MAX_LOCKS) {
		printf("Lock is out of bounds. Passed: %i\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}

	/*if you're here then you have no errors, acquire lock*/
	/*printf("Acquiring lock: %s\n", kernelLocks[*currentThread->processId][lockNum]->lock->getName());*/
		
	
	kernelLockTableLock->Release();
	kernelLocks[*currentThread->processId][lockNum]->lock->Acquire();

	
}

//syscall #13
void LockRelease_Syscall(int lockNum) {
	kernelLockTableLock->Acquire();

	/*check if the lock has been initialized*/
	if(kernelLocks[*currentThread->processId][lockNum] == NULL) {
		printf("Lock %i has not been initialized.\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}

	/*check if this process can access this lock by checking the address space*/
	if(kernelLocks[*currentThread->processId][lockNum]->addrSpace != currentThread->space) {
		/*printf("You do not own that lock. Thread#: %i, Lock#: %i\n", kernelLocks[*currentThread->processId][lockNum]->addrSpace, currentThread->space);*/
		printf("You do not own that lock.\n");
		kernelLockTableLock->Release();
		return;
	}
	/*check if that lock has been deleted*/
	if(kernelLocks[*currentThread->processId][lockNum]->isDeleted == true || kernelLocks[*currentThread->processId][lockNum]->isToBeDeleted == true) {
		printf("That lock has been deleted.\n");
		kernelLockTableLock->Release();
		return;
	}
	/*Delete lock if it needs to be deleted*/
	if((kernelLocks[*currentThread->processId][lockNum]->isToBeDeleted == true) && (kernelLocks[*currentThread->processId][lockNum]->lock->getQueueSize() == 0) && (kernelLocks[*currentThread->processId][lockNum]->isDeleted == false)) {
		kernelLocks[*currentThread->processId][lockNum]->isDeleted = true;
		freeKernelLockBmp->Clear(lockNum);
	}
	if(lockNum < 0 || lockNum > MAX_LOCKS) {
		printf("Lock is out of bounds. Passed: %i\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}
	/*if you're here then you have no errors, release lock*/
	/*printf("Releasing lock: %s\n", kernelLocks[*currentThread->processId][lockNum]->lock->getName());*/

	kernelLocks[*currentThread->processId][lockNum]->lock->Release();

	kernelLockTableLock->Release();
	
}

//syscall #14
void LockDelete_Syscall(int lockNum) {
	kernelLockTableLock->Acquire();

	/*check if the lock has been initialized*/
	if(kernelLocks[*currentThread->processId][lockNum] == NULL) {
		printf("Lock %i has not been initialized.\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}

	/*check if this process can access this lock by checking the address space*/
	if(kernelLocks[*currentThread->processId][lockNum]->addrSpace != currentThread->space) {
		/*printf("You do not own that lock. Thread#: %i, Lock#: %i\n", kernelLocks[*currentThread->processId][lockNum]->addrSpace, currentThread->space);*/
		printf("You do not own that lock.\n");
		kernelLockTableLock->Release();
		return;
	}
	/*if the lock has already been deleted or marked for deletion, then do nothing*/
	if(kernelLocks[*currentThread->processId][lockNum]->isDeleted == true || kernelLocks[*currentThread->processId][lockNum]->isToBeDeleted == true) {
		printf("Lock has already been deleted\n");
		kernelLockTableLock->Release();
		return;
	}
	if(lockNum < 0 || lockNum > MAX_LOCKS) {
		printf("Lock is out of bounds. Passed: %i\n", lockNum);
		kernelLockTableLock->Release();
		return;
	}

	/*no errors, so mark lock for deletion*/
	printf("Deleting lock: %i\n", lockNum);
	kernelLocks[*currentThread->processId][lockNum]->isToBeDeleted = true;
	
	kernelLockTableLock->Release();
}

int CVCreate_Syscall(unsigned int vaddr, int len) {
	char *buf;
	
	/*makes buf a character array of size len (so it can be used) or returns*/
	if ( !(buf = new char[len+1]) ) {
		printf("%s","Error allocating kernel buffer in Create Lock\n");
		return(-1);
	}
	
	/*copies the data from the virtual address into buf*/
	if ( copyin(vaddr, len, buf) == -1 ) {
		printf("%s","Bad pointer passed to Create CV: data not copied\n");
		delete[] buf;
		return(-1);
	}
	
	#ifdef NETWORK
	    	int rv = ClientCreateCV(buf);
		networkConditions[*currentThread->processId][rv] = buf;
		return rv;
	#endif
	/*find empty space in bitmap*/
	nextConditionLocation = freeKernelCVBmp->Find();
	
	/*if no free space for CVs, then let the user know*/
	if(nextConditionLocation == -1) {
		printf("No more free spaces. You have reached the maximum number of CVs! New CVs cannot be made until other ones are deleted.\n");
		return(-1);
	}
	
	/*if we found a free space, make a new CV*/
	
	buf[len] = '\0';
	printf("Making new CV named %s\nIt's position in the kernelConditions is %i\n", buf, nextLockLocation);
	/*no errors, so make the CV and add it to the global array of CVs*/
	kernelConditions[*currentThread->processId][nextConditionLocation] = new KernelCV();
	kernelConditions[*currentThread->processId][nextConditionLocation]->cond = new Condition(buf);
	kernelConditions[*currentThread->processId][nextConditionLocation]->addrSpace = currentThread->space;
	kernelConditions[*currentThread->processId][nextConditionLocation]->isToBeDeleted = false;
	kernelConditions[*currentThread->processId][nextConditionLocation]->isDeleted = false;
	/*return the int so the process can use the CV*/
	return(nextConditionLocation);
}

void Signal_Syscall(int conditionIndex, int lockIndex)
{
	/* 	1. First thing must be checking whether it is valid
		2. If all data is valid, do task
	*/
	/*
		Validation for */
	
	/* If the index is less than zero or the lock has not been created yet */
	/* Accessing shared data. Acquiring kernel lock for table lock */
	kernelLockTableLock->Acquire(); 
	if (lockIndex < 0 || lockIndex > MAX_LOCKS) 
		{
			kernelLockTableLock->Release();
			DEBUG('a', "Signal Lock Index is out of bounds \n");
			printf("Signal Lock Index is out of bounds\n");
			return;
		}
	/* Check whether lock belongs to another process */
	if (kernelLocks[*currentThread->processId][lockIndex]->addrSpace != currentThread->space)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock does not belong to currentThread\n");
		printf("The lock does not belong Signal to currentThread\n");
		return;
	}
	/* Check whether the lock even exists */
	if (kernelLocks[*currentThread->processId][lockIndex]->isDeleted == 1)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock has been deleted");
		printf("Signal The lock has been deleted");
		return;
	}
	
	if (kernelLocks[*currentThread->processId][lockIndex]->lock == 0)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "Signal The lock is NULL");
		return;
	}
	kernelLockTableLock->Release();
	kernelConditionTableLock->Acquire();
	if (conditionIndex < 0 || conditionIndex > MAX_CVS) 
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "Condition index is out of bounds \n");
		printf("Signal Condition index is out of bounds \n");
		return;
	}
	if (kernelConditions[*currentThread->processId][conditionIndex]->addrSpace != currentThread->space)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition does not belong to currentThread address space\n");
		printf("Signal The condition does not belong to currentThread address space\n");
		return;
	}
	/* Check whether the condition even exists */
	if (kernelConditions[*currentThread->processId][conditionIndex]->isDeleted == 1)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition has been deleted");
		return;
	}
	
	if (kernelConditions[*currentThread->processId][conditionIndex]->cond == 0)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition is NULL");
		return;
	}
	kernelConditionTableLock->Release();
	kernelConditions[*currentThread->processId][conditionIndex]->cond->Signal(kernelLocks[*currentThread->processId][lockIndex]->lock);
	
}

void Wait_Syscall(int conditionIndex, int lockIndex)
{
	printf("here\n");
/*
		Validation for */
	
	/* If the index is less than zero or the lock has not been created yet */
	/* Accessing shared data. Acquiring kernel lock for table lock */
	kernelLockTableLock->Acquire(); 
		
	if (lockIndex < 0 || lockIndex > MAX_LOCKS) 
		{
			kernelLockTableLock->Release();
			DEBUG('a', "Lock Index is out of bounds \n");
			printf("Lock Index is out of bounds \n");
			return;
		}
	/* Check whether lock belongs to another process */
	if (kernelLocks[*currentThread->processId][lockIndex]->addrSpace != currentThread->space)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock does not belong to currentThread\n");
		printf("The lock does not belong to currentThread\n");
		return;
	}
	/* Check whether the lock even exists */
	if (kernelLocks[*currentThread->processId][lockIndex]->isDeleted == 1)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock has been deleted");
		printf("The lock has been deleted");
		return;
	}
	
	if (kernelLocks[*currentThread->processId][lockIndex]->lock == 0)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock is NULL");
		printf("The lock is NULL");
		return;
	}
	kernelLockTableLock->Release();
	kernelConditionTableLock->Acquire();
	
	if (conditionIndex < 0 || conditionIndex > MAX_CVS) 
		{
			kernelConditionTableLock->Release();
			DEBUG('a', "Condition index is out of bounds \n");
			printf("Condition index is out of bounds \n");
			return;
		}
	if (kernelConditions[*currentThread->processId][conditionIndex]->addrSpace != currentThread->space)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition does not belong to currentThread address space\n");
		printf("The condition does not belong to currentThread address space\n");
		return;
	}
	/* Check whether the condition even exists */
	if (kernelConditions[*currentThread->processId][conditionIndex]->isDeleted == 1)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition has been deleted");
		printf("The condition has been deleted\n");
		return;
	}
	
	if (kernelConditions[*currentThread->processId][conditionIndex]->cond == 0)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition is NULL");
		printf("The condition is NULL\n");
		return;
	}
	
	kernelConditionTableLock->Release();
	kernelConditions[*currentThread->processId][conditionIndex]->cond->Wait(kernelLocks[*currentThread->processId][lockIndex]->lock);
	printf("there\n");

	

}

void Broadcast_Syscall(int conditionIndex, int lockIndex)
{
/*
		Validation for */
	
	/* If the index is less than zero or the lock has not been created yet */
	/* Accessing shared data. Acquiring kernel lock for table lock */
	kernelLockTableLock->Acquire();
	printf("Things\n");
	if (lockIndex < 0 || lockIndex > MAX_LOCKS) 
		{
			kernelLockTableLock->Release();
			DEBUG('a', "Lock Index broadcast is out of bounds \n");
			printf("Lock Index broadcast is out of bounds \n");
			return;
		}
	/* Check whether lock belongs to another process */
	if (kernelLocks[*currentThread->processId][lockIndex]->addrSpace != currentThread->space)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock does not belong to currentThread\n");
		printf("The lock does not belong to currentThread\n");
		return;
	}
	/* Check whether the lock even exists */
	if (kernelLocks[*currentThread->processId][lockIndex]->isDeleted == 1)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock has been deleted");
		return;
	}
	
	if (kernelLocks[*currentThread->processId][lockIndex]->lock == 0)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock is NULL");
		return;
	}
	kernelLockTableLock->Release();
	kernelConditionTableLock->Acquire();
	if (conditionIndex < 0 || conditionIndex > MAX_CVS) 
		{
			kernelConditionTableLock->Release();
			DEBUG('a', "Condition index is out of bounds \n");
			printf("Broadcast Condition index is out of bounds \n");
			return;
		}
	if (kernelConditions[*currentThread->processId][conditionIndex]->addrSpace != currentThread->space)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition does not belong to currentThread address space\n");
		return;
	}
	/* Check whether the condition even exists */
	if (kernelConditions[*currentThread->processId][conditionIndex]->isDeleted == 1)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition has been deleted");
		return;
	}
	
	if (kernelConditions[*currentThread->processId][conditionIndex]->cond == 0)
	{
		kernelConditionTableLock->Release();
		DEBUG('a', "The condition is NULL");
		return;
	}
	kernelConditionTableLock->Release();
	kernelConditions[*currentThread->processId][conditionIndex]->cond->Broadcast(kernelLocks[*currentThread->processId][lockIndex]->lock);
	

}

void CVDelete_Syscall(int cvNum) {
	/*check if this process can access this lock by checking the address space*/
	if(kernelConditions[*currentThread->processId][cvNum]->addrSpace != currentThread->space) {
		/*printf("You do not own that CV. Thread#: %i, CV#: %i\n", kernelConditions[*currentThread->processId][cvNum]->addrSpace, currentThread->space);*/
		printf("You do not own that CV.\n");
		return;
	}
	/*if the CV has already been deleted or marked for deletion, then do nothing*/
	if(kernelConditions[*currentThread->processId][cvNum]->isDeleted == true || kernelConditions[*currentThread->processId][cvNum]->isToBeDeleted == true) {
		printf("Lock has already been deleted\n");
		return;
	}
	/*no errors, so mark CV for deletion*/
	freeKernelCVBmp->Clear(cvNum);
	kernelConditions[*currentThread->processId][cvNum]->isToBeDeleted = true;
}

int MVCreate_Syscall(char name, int len, int arrSize) {
	char *buf;
	
	/*makes buf a character array of size len (so it can be used) or returns*/
	if ( !(buf = new char[len+1]) ) {
		printf("%s","Error allocating kernel buffer in Create MV\n");
		return(-1);
	}
	
	/*copies the data from the virtual address into buf*/
	if ( copyin(name, len, buf) == -1 ) {
		printf("%s","Bad pointer passed to Create MV: data not copied\n");
		delete[] buf;
		return(-1);
	}

	int rv = ClientCreateMV(buf,arrSize);
	networkMonitors[*currentThread->processId][rv] = buf;
	return rv;
	
	/*find empty space in bitmap*/
	nextMonitorLocation = freeKernelMVBmp->Find();
	
	/*if no free space for MVs, then let the user know*/
	if(nextMonitorLocation == -1) {
		printf("No more free spaces. You have reached the maximum number of MVs! New MVs cannot be made until other ones are deleted.\n");
		return(-1);
	}

        if (arrSize > 100) {
	  printf("Array size is too large.\n");
	  return(-1);
	}
	
	/*if we found a free space, make a new MV*/
	
	buf[len] = '\0';
	printf("Making new MV named %s\nIt's position in the kernelMonitors is %i\n", buf, nextLockLocation);
	/*no errors, so make the MV and add it to the global array of MVs*/
	kernelMonitors[*currentThread->processId][nextMonitorLocation] = new KernelMV();
	kernelMonitors[*currentThread->processId][nextMonitorLocation]->size = arrSize;
	kernelMonitors[*currentThread->processId][nextMonitorLocation]->addrSpace = currentThread->space;
	kernelMonitors[*currentThread->processId][nextMonitorLocation]->isToBeDeleted = false;
	kernelMonitors[*currentThread->processId][nextMonitorLocation]->isDeleted = false;
	/*return the int so the process can use the MV*/
	return(nextMonitorLocation);
}

int MVGetValue_Syscall(int monitorIndex, int lockIndex) {
	/* If the index is less than zero or the lock has not been created yet */
	/* Accessing shared data. Acquiring kernel lock for table lock */
	kernelLockTableLock->Acquire(); 
		
	if (lockIndex < 0 || lockIndex > MAX_LOCKS) 
		{
			kernelLockTableLock->Release();
			DEBUG('a', "Lock Index is out of bounds \n");
			printf("Lock Index is out of bounds \n");
			return NULL;
		}
	/* Check whether lock belongs to another process */
	if (kernelLocks[*currentThread->processId][lockIndex]->addrSpace != currentThread->space)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock does not belong to currentThread\n");
		printf("The lock does not belong to currentThread\n");
		return NULL;
	}
	/* Check whether the lock even exists */
	if (kernelLocks[*currentThread->processId][lockIndex]->isDeleted == 1)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock has been deleted");
		printf("The lock has been deleted");
		return NULL;
	}
	
	if (kernelLocks[*currentThread->processId][lockIndex]->lock == 0)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock is NULL");
		printf("The lock is NULL");
		return NULL;
	}
	kernelLockTableLock->Release();
	kernelMonitorTableLock->Acquire();
	
	if (monitorIndex < 0 || monitorIndex > MAX_MVS) 
		{
			kernelMonitorTableLock->Release();
			DEBUG('a', "Monitor index is out of bounds \n");
			printf("Monitor index is out of bounds \n");
			return NULL;
		}
	if (kernelMonitors[*currentThread->processId][monitorIndex]->addrSpace != currentThread->space)
	{
		kernelMonitorTableLock->Release();
		DEBUG('a', "The monitor does not belong to currentThread address space\n");
		printf("The monitor does not belong to currentThread address space\n");
		return NULL;
	}
	/* Check whether the monitor even exists */
	if (kernelMonitors[*currentThread->processId][monitorIndex]->isDeleted == 1)
	{
		kernelMonitorTableLock->Release();
		DEBUG('a', "The monitor has been deleted");
		printf("The monitor has been deleted\n");
		return NULL;
	}
	
       	kernelMonitorTableLock->Release();
	return *kernelMonitors[*currentThread->processId][monitorIndex]->values;
}

int MVSetValue_Syscall(int monitorIndex, int lockIndex, int monValIndex, int newVal) {
	/* If the index is less than zero or the lock has not been created yet */
	/* Accessing shared data. Acquiring kernel lock for table lock */
	kernelLockTableLock->Acquire(); 
		
	if (lockIndex < 0 || lockIndex > MAX_LOCKS) 
		{
			kernelLockTableLock->Release();
			DEBUG('a', "Lock Index is out of bounds \n");
			printf("Lock Index is out of bounds \n");
			return(-1);
		}
	/* Check whether lock belongs to another process */
	if (kernelLocks[*currentThread->processId][lockIndex]->addrSpace != currentThread->space)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock does not belong to currentThread\n");
		printf("The lock does not belong to currentThread\n");
		return(-1);
	}
	/* Check whether the lock even exists */
	if (kernelLocks[*currentThread->processId][lockIndex]->isDeleted == 1)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock has been deleted");
		printf("The lock has been deleted");
		return(-1);
	}
	
	if (kernelLocks[*currentThread->processId][lockIndex]->lock == 0)
	{
		kernelLockTableLock->Release();
		DEBUG('a', "The lock is NULL");
		printf("The lock is NULL");
		return(-1);
	}
	kernelLockTableLock->Release();
	kernelMonitorTableLock->Acquire();
	
	if (monitorIndex < 0 || monitorIndex > MAX_MVS) 
		{
			kernelMonitorTableLock->Release();
			DEBUG('a', "Monitor index is out of bounds \n");
			printf("Monitor index is out of bounds \n");
			return(-1);
		}
	if (kernelMonitors[*currentThread->processId][monitorIndex]->addrSpace != currentThread->space)
	{
		kernelMonitorTableLock->Release();
		DEBUG('a', "The monitor does not belong to currentThread address space\n");
		printf("The monitor does not belong to currentThread address space\n");
		return(-1);
	}
	/* Check whether the monitor even exists */
	if (kernelMonitors[*currentThread->processId][monitorIndex]->isDeleted == 1)
	{
		kernelMonitorTableLock->Release();
		DEBUG('a', "The monitor has been deleted");
		printf("The monitor has been deleted\n");
		return(-1);
	}
	
	if (monValIndex < 0 || monValIndex > kernelMonitors[*currentThread->processId][monitorIndex]->size)
	{
		kernelMonitorTableLock->Release();
		DEBUG('a', "The monitor index specified is out of bounds.");
		printf("The monitor index is invalid.\n");
		return(-1);
	}
	
	kernelMonitors[*currentThread->processId][monitorIndex]->values[monValIndex] = newVal;
	kernelMonitorTableLock->Release();
	  return(0);
}

void MVDelete_Syscall(int mvNum) {
	/*check if this process can access this lock by checking the address space*/
	if(kernelMonitors[*currentThread->processId][mvNum]->addrSpace != currentThread->space) {
		/*printf("You do not own that MV. Thread#: %i, MV#: %i\n", kernelMonitors[*currentThread->processId][mvNum]->addrSpace, currentThread->space);*/
		printf("You do not own that MV.\n");
		return;
	}
	/*if the MV has already been deleted or marked for deletion, then do nothing*/
	if(kernelMonitors[*currentThread->processId][mvNum]->isDeleted == true || kernelMonitors[*currentThread->processId][mvNum]->isToBeDeleted == true) {
		printf("MV has already been deleted\n");
		return;
	}
	/*no errors, so mark MV for deletion*/
	freeKernelMVBmp->Clear(mvNum);
	kernelMonitors[*currentThread->processId][mvNum]->isToBeDeleted = true;
}


int Scan_Syscall() {
	int iInput;
	scanf("%i", &iInput);
	return iInput;
}

// used only for unit test
int TestCmdLine() {
	return pEvict;
}
void TestFileIO() {
	int place1 = swapBmp->Find();
	char* testData = "test data 1";
	char* returnData;

	printf("Reading the swap file. Should return garbage.\n");
	//swapFile->ReadAt(returnData, sizeof(testData), place1);
	//printf("%s\n", returnData); /*should return garbage*/

	/*printf("Writing \"%s\" to swap file.\n", testData);
	if(swapFile->WriteAt(testData, sizeof(testData), place1) == 0) {
		printf("Write failed!\n");
		return;
	}
	else
		printf("Write succeeded.\n");

	printf("Reading from swap file again. Should return the string we passed.\n");
	if(swapFile->ReadAt(returnData, sizeof(testData), place1) == 0) {
		printf("Read Failed!\n");
		return;
	}
	printf("%s\n", *returnData);*/ /*should return the string in testData*/
}


void ExceptionHandler(ExceptionType which) {
    int type = machine->ReadRegister(2); // Which syscall?
    int rv=0; 	// the return value from a syscall

    if ( which == SyscallException ) {
	switch (type) {
	    default:
		DEBUG('a', "Unknown syscall - shutting down.\n");
	    case SC_Halt:
		DEBUG('a', "Shutdown, initiated by user program.\n");
		interrupt->Halt();
		break;
		
	    case SC_Create:
		DEBUG('a', "Create syscall.\n");
		Create_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
		
	    case SC_Open:
		DEBUG('a', "Open syscall.\n");
		rv = Open_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
		
	    case SC_Write:
		DEBUG('a', "Write syscall.\n");
		Write_Syscall(machine->ReadRegister(4),
			      machine->ReadRegister(5),
			      machine->ReadRegister(6));
		break;

	    case SC_Write1:
		DEBUG('a', "Write1 syscall.\n");
		Write1_Syscall(machine->ReadRegister(4),
			      machine->ReadRegister(5),
			      machine->ReadRegister(6),
			      machine->ReadRegister(7));
		break;
		
	    case SC_Read:
		DEBUG('a', "Read syscall.\n");
		rv = Read_Syscall(machine->ReadRegister(4),
			      machine->ReadRegister(5),
			      machine->ReadRegister(6));
		break;
	    case SC_Close:
		DEBUG('a', "Close syscall.\n");
		Close_Syscall(machine->ReadRegister(4));
		break;
	    case SC_LockCreate:
	   	
		DEBUG('a', "Create Lock syscall.\n");
		rv = LockCreate_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

	    case SC_LockAcquire:
	   	#ifdef NETWORK
	    		rv = ClientAcquireLock(networkLocks[*currentThread->processId][machine->ReadRegister(4)]);
	    		break;
	    	#endif
		DEBUG('a', "Acquire Lock syscall.\n");
		LockAcquire_Syscall(machine->ReadRegister(4));
		break;

	    case SC_LockRelease:
	        #ifdef NETWORK
	    		rv = ClientReleaseLock(networkLocks[*currentThread->processId][machine->ReadRegister(4)]);
	    		break;
	    	#endif
		DEBUG('a', "Release Lock syscall.\n");
		LockRelease_Syscall(machine->ReadRegister(4));
		break;

	    case SC_LockDelete:
	    	#ifdef NETWORK
	    		rv = ClientDeleteLock(networkLocks[*currentThread->processId][machine->ReadRegister(4)]);
	    		break;
	    	#endif
		DEBUG('a', "Delete Lock syscall.\n");
		LockDelete_Syscall(machine->ReadRegister(4));
		break;

	    case SC_CVCreate:
			DEBUG('a', "Create CV syscall.\n");
			rv = CVCreate_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

	    case SC_Signal:
		#ifdef NETWORK
	    		rv = ClientSignal(networkConditions[*currentThread->processId][machine->ReadRegister(4)],networkLocks[*currentThread->processId][machine->ReadRegister(5)]);
	    		break;
	    	#endif
		DEBUG('a', "Signal syscall.\n");
		Signal_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
		
	    case SC_Wait:
		#ifdef NETWORK
	    		rv = ClientWait(networkConditions[*currentThread->processId][machine->ReadRegister(4)],networkLocks[*currentThread->processId][machine->ReadRegister(5)]);
	    		break;
	    	#endif
		DEBUG('a', "Wait syscall.\n");
		Wait_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;
		
	    case SC_Broadcast:
		#ifdef NETWORK
	    		rv = ClientBroadcast(networkConditions[*currentThread->processId][machine->ReadRegister(4)],networkLocks[*currentThread->processId][machine->ReadRegister(5)]);
	    		break;
	    	#endif
		DEBUG('a', "Broadcast syscall.\n");
		Broadcast_Syscall(machine->ReadRegister(4), machine->ReadRegister(5));
		break;

	    case SC_CVDelete:
	    	#ifdef NETWORK
	    		rv = ClientBroadcast(networkConditions[*currentThread->processId][machine->ReadRegister(4)],networkLocks[*currentThread->processId][machine->ReadRegister(5)]);
	    		break;
	    	#endif
		DEBUG('a', "Delete CV syscall.\n");
		CVDelete_Syscall(machine->ReadRegister(4));
		break;

	    case SC_MVCreate:
                DEBUG('a', "Create MV syscall.\n");
		#ifdef NETWORK
		MVCreate_Syscall(machine->ReadRegister(4), machine->ReadRegister(5), machine->ReadRegister(6));

		#endif
		break;

            case SC_MVGetValue:
		DEBUG('a', "Get MV value syscall.\n");
		
		#ifdef NETWORK
	    		rv = ClientMVGet(networkMonitors[*currentThread->processId][machine->ReadRegister(5)],machine->ReadRegister(4));
	    		break;
	    	#endif
		break;


	    case SC_MVSetValue:
			DEBUG('a', "Set MV value syscall.\n");
			rv = ClientMVSet(networkMonitors[*currentThread->processId][machine->ReadRegister(5)],machine->ReadRegister(4), machine->ReadRegister(6));
			break;

	    case SC_MVDelete:
			DEBUG('a', "Delete MV syscall.\n");
			rv = ClientMVDelete(networkMonitors[*currentThread->processId][machine->ReadRegister(4)]);
		break;

	    case SC_Yield:
			DEBUG('a',"Yielding thread.\n");
			currentThread->Yield();
			break;
	    case SC_Fork:
	   		processTable->lockProcess();
	    		DEBUG('a',"Forking thread.\n");

			Thread* t = new Thread("Thread");
			t->space=currentThread->space;
			processTable->addThread(t);
			t->Fork((VoidFunctionPtr)kernel_thread,machine->ReadRegister(4));
			processTable->releaseProcess();
			break;
	    case SC_Exit:
			printf("%i\n", machine->ReadRegister(4));
	
			processTable->lockProcess();
			if(processTable->processCounter==1)
			{
				
				if(processTable->getExecutingThreads()==1)
				{
				  printf("Exiting Program\n");
				  delete swapFile;
					interrupt->Halt();
					
				}
				else
				{
					printf("%i\n",processTable->getExecutingThreads());
					currentThread->space->ClearStackPage(*(currentThread->stackPage));
					processTable->removeThread(*(currentThread->threadId));
					printf("Ending thread in last Process %i\n",*(currentThread->processId));				
					processTable->releaseProcess();
					currentThread->Finish();
				}
				
			}
			else
			{
				if(processTable->getExecutingThreads()==1)
				{
					currentThread->space->ClearProcessPages();
					processTable->removeProcess();
      					printf("Ending Process %i\n",*(currentThread->processId));
      					processTable->releaseProcess();
					currentThread->Finish();
				}
				else 
				{
					currentThread->space->ClearStackPage(*(currentThread->stackPage));
					processTable->removeThread(*(currentThread->threadId));
					printf("Ending thread in Process %i\n",*(currentThread->processId));
					processTable->releaseProcess();
					currentThread->Finish();
				}
		   		
			}
			break;
	   case SC_Exec:
	   		processTable->lockTable();
			int vaddr = machine->ReadRegister(4);
			int* paddr;
			int len = machine->ReadRegister(5);
 			AddrSpace *space;
			char *buf = new char[len+1];	// Kernel buffer to put the name in
			
  			if (!buf) return;

   			if( copyin(vaddr,len,buf) == -1 ) {
				printf("%s","Bad pointer passed to Exec\n");
				delete buf;
				return;
    		}

    		buf[len]='\0';
			
			OpenFile* f = fileSystem->Open(buf);

   			if (f == NULL) {
				printf("Unable to open file\n ");
				return;
  			}
			Thread* t2 = new Thread("exec_thread");
			space = new AddrSpace(f);
			t2->space = space;
			*(space->processId)=processTable->addProcess(space,t2);
			t2->Fork((VoidFunctionPtr)kernel_thread,0);
			processTable->releaseTable();
			break;
	    case SC_Rand:
	    		rv = rand();
	    		break;
		case SC_GetChar:
			rv = getchar();
			break;
		case SC_Scan:
			rv = Scan_Syscall();
			break;
		case SC_TestCmdLine:
			rv = TestCmdLine();
			break;
		case SC_TestFileIO:
			TestFileIO();
		
		   	
			
	}

	// Put in the return value and increment the PC
	machine->WriteRegister(2,rv);
	machine->WriteRegister(PrevPCReg,machine->ReadRegister(PCReg));
	machine->WriteRegister(PCReg,machine->ReadRegister(NextPCReg));
	machine->WriteRegister(NextPCReg,machine->ReadRegister(PCReg)+4);
	return;
    }
	else if(which==PageFaultException)	//page does not exist in physical(?) memory
	{
		
		/*//propagate dirty bits from tlb to ipt
		
		for(int i = 0; i < 4; i++) {
		IntStatus oldLevel = interrupt->SetLevel(IntOff);
			if(machine->tlb[i].dirty == true) {
				IPT[machine->tlb[i].physicalPage].dirty = true;
			}
		interrupt->SetLevel(oldLevel);
		}

		int physicalPage = -1;
		
		IntStatus oldLevel = interrupt->SetLevel(IntOff);
		int VPN = machine->ReadRegister(39)/PageSize;
		interrupt->SetLevel(oldLevel);
		
		iptLock->Acquire();

		//iterate through IPT to find the page to be evicted
		for(int i = 0; i < machine->pageTableSize; i++) {
			if(IPT[i].valid == true) {
				if(IPT[i].virtualPage == VPN) {
					if(IPT[i].addrSpace == currentThread->space) {
						//IPT hit

						physicalPage = i;
						break;
					}
				}
			}
		}

		//Handle IPT miss
		if (physicalPage == -1)
		{

			physicalPage = handleIPTMiss(VPN);
		}

		//printf("page fault VPN is %i\n",VPN);
		oldLevel = interrupt->SetLevel(IntOff);
				
		machine->tlb[currentTLB].virtualPage=VPN;

		machine->tlb[currentTLB].physicalPage=physicalPage;

		machine->tlb[currentTLB].valid=currentThread->space->pageTable[VPN].valid;

		machine->tlb[currentTLB].dirty=currentThread->space->pageTable[VPN].dirty;

		machine->tlb[currentTLB].use=currentThread->space->pageTable[VPN].use;

		machine->tlb[currentTLB].readOnly=currentThread->space->pageTable[VPN].readOnly;
		
		machine->tlb[currentTLB].valid=currentThread->space->pageTable[VPN].valid;
		currentTLB+=1;
		currentTLB = currentTLB%TLBSize;
		/*for(int i = 0; i<TLBSize;i++)
		{
			printf("TLB[%i] is valid is %i, ppn is %i, vpn is %i\n",i,machine->tlb[i].valid,machine->tlb[i].physicalPage,machine->tlb[i].virtualPage);
		}*/
		
		/*interrupt->SetLevel(oldLevel);

		IPT[physicalPage].inUse = false;
		iptLock->Release();*/
		

	}
	else {
      cout<<"Unexpected user mode exception - which:"<<which<<"  type:"<< type<<endl;
      interrupt->Halt();
    }
   
}

int handleIPTMiss (int VPN)
{
/*	int index;
	mbmLock->Acquire();
	index = PhysicalMemoryMap->Find();
	mbmLock->Release();
	
	//IntStatus testLevel = interrupt->SetLevel(IntOff);
	//Essentially this is evict a page function
	if (index == -1)
	{
		//find page in memory, mark it for deletion, set index equal to it's address
		//iptLock->Acquire();
		//printf("The bitmap returned -1 and the memory is full\n");
	
		//select page for eviction and remove it
		if(pEvict == 0)	//RAND policy
		{
			int randNum;
			//wait until that ipt index is not busy
			do{
				randNum = rand()%NumPhysPages;
				//iptLock->Acquire();
				if(!IPT[randNum].inUse) {
					IPT[randNum].inUse = true;
					//iptLock->Release();
					break;
				}
				//iptLock->Release();
			}while(true);

			//set index to random number we have
			index = randNum;
			
			//iptLock->Acquire();
			if(IPT[randNum].dirty == true) {
				//save it to the swapfile
				
				int swapPos = swapBmp->Find();
			
				swapFile->WriteAt(&(machine->mainMemory[index*PageSize]), PageSize, swapPos*PageSize);
				IPT[index].addrSpace->spaceLock->Acquire();
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].diskLocation = 1;
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].swapLocation = swapPos*PageSize;
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].physicalPage = -1;
				IPT[index].addrSpace->spaceLock->Release();
			}

			//set in use variable back to false
			IPT[index].inUse = true;
			//iptLock->Release();
		}
		else	//FIFO policy (default)
		{
		
		//printf("Index is %i\n",index);
			//wait until that ipt index is not busy
			do{
				//iptLock->Acquire();
				//printf("%i\n",toBeDeletedQueue[0]);
				if(!IPT[toBeDeletedQueue[0]].inUse) {
					IPT[toBeDeletedQueue[0]].inUse = true;
					
					break;
				}
				//iptLock->Release();
			}while(true);
				
			index = toBeDeletedQueue[0];
			
			//set index to index in front of queue
			
			
			//check if page we are evicting is dirty
		
			if(IPT[toBeDeletedQueue[0]].dirty == true) {
				//save it to the swapfile
				int swapPos=-1;
				if(currentThread->space->pageTable[IPT[index].virtualPage].swapLocation==-1)
					swapPos = swapBmp->Find();
				else
					swapPos = IPT[index].addrSpace->pageTable[IPT[index].virtualPage].swapLocation/PageSize;
					
				
				IPT[index].addrSpace->spaceLock->Acquire();
				swapFile->WriteAt(&(machine->mainMemory[index*PageSize]), PageSize, swapPos*PageSize);
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].diskLocation = 1;
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].swapLocation = swapPos*PageSize;
				IPT[index].addrSpace->pageTable[IPT[index].virtualPage].physicalPage = -1;
				IPT[index].addrSpace->spaceLock->Release();	
				printf("Writing to Swap File VPN: %i, PPN: %i, swap location: %i\n",IPT[index].virtualPage,IPT[index].physicalPage,IPT[index].addrSpace->pageTable[IPT[index].virtualPage].swapLocation);
			}

			
			//removes the page in the front of the queue (by overwriting it and moving everything down)

			for(int i = 1; i < tbdQSize; i++) {
				toBeDeletedQueue[i-1] = toBeDeletedQueue[i];
			}
			tbdQSize--;
			
			//interrupt->Halt();
			
			//set in use variable back to false
		
			IPT[index].valid = false;
			//iptLock->Release();
		
		}
		IntStatus oldLevel = interrupt->SetLevel(IntOff);
		for(int i = 0; i<TLBSize;i++)
		{
			if(machine->tlb[i].physicalPage == index)
			{
				
				machine->tlb[i].valid = false;
				
			}
		}
		interrupt->SetLevel(oldLevel);
	//	iptLock->Release();
	}
		
	
		//printf("VPN is %i, Index is %i\n",VPN,index);
	//iptLock->Acquire();
	currentThread->space->spaceLock->Acquire();
	currentThread->space->pageTable[VPN].physicalPage = index;
		
	

		//The disklocation is in the executable
	if (currentThread->space->pageTable[VPN].diskLocation == -1)
	{
				 /* Index * pageSize is the physical Address */
	/*	printf("Reading from Executable File at %i\n",currentThread->space->pageTable[VPN].inFileAddr);
		currentThread->space->openFile->ReadAt(&(machine->mainMemory[index*PageSize]),PageSize, currentThread->space->pageTable[VPN].inFileAddr);
	}

	else if (currentThread->space->pageTable[VPN].diskLocation == 1)
	{
	printf("Reading from Swap File at %i\n",currentThread->space->pageTable[VPN].swapLocation);
		swapFile->ReadAt(&(machine->mainMemory[index*PageSize]),PageSize, currentThread->space->pageTable[VPN].swapLocation);
	}
	else
	{
		printf("Not on disk\n");
	}

	currentThread->space->pageTable[VPN].valid = true;
	currentThread->space->spaceLock->Release();
	
	IPT[index].physicalPage = index;
	IPT[index].valid = true;
	IPT[index].virtualPage = VPN;
	IPT[index].readOnly = false;
	IPT[index].use = false;
	IPT[index].dirty = false;
	IPT[index].addrSpace = currentThread->space;
	
		
	printf("New IPT entiry IPT[%i] physicalAddr: %i\n IPT[%i].virtualPage: %i\n",index,index*PageSize, index, VPN);
		
	if(pEvict!=0)
	{
		//add page to queue and increment when allocating a new page of memory
		toBeDeletedQueue[tbdQSize] = index;
		tbdQSize++;
		
	}

		///interrupt->SetLevel(testLevel);
	//iptLock->Release();
	return index;*/
	
}


void kernel_thread(int vaddr)
{
	
	if(vaddr>=0)
	{
		
		processTable->lockProcess();

		currentThread->space->InitRegisters();
		machine->WriteRegister(PCReg,vaddr);
		machine->WriteRegister(NextPCReg,machine->ReadRegister(PCReg)+4);
		currentThread->stackReg = new int;
		currentThread->space->RestoreState();
		*(currentThread->stackPage) = currentThread->space->stackMap->Find();
		*(currentThread->stackReg)=(*(currentThread->space->codeDataPages)+((*(currentThread->stackPage)+1)*8))*PageSize-16;
		machine->WriteRegister(StackReg,*(currentThread->stackReg));
		processTable->releaseProcess();
		
			
		machine->Run();
	}
	
}
